package org.aeon.colorfulplanebattle.view.logic;

import org.aeon.colorfulplanebattle.constant.ColorE;
import org.aeon.colorfulplanebattle.flying.Utils;
import org.aeon.colorfulplanebattle.flying.entity.*;
import org.aeon.colorfulplanebattle.flying.thread.BulletThread;
import org.aeon.colorfulplanebattle.flying.thread.HitThread;
import org.aeon.colorfulplanebattle.flying.thread.ShipThread;
import org.aeon.colorfulplanebattle.flying.thread.SprinkleThread;
import org.aeon.colorfulplanebattle.view.GameState;

import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import java.util.TimerTask;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static org.aeon.colorfulplanebattle.constant.GameBasisConstant.*;

/**
 * @author: MissingAeon
 * @date: 2024/1/10 10:44
 * @description: 游戏计时器
 */
public class GameJudgeTask extends TimerTask {
    private final GameState gameState;                      // 游戏状态类
    private final Plane myPlane;                            // 玩家飞机
    private final List<Ship> ships;                         // 敌方飞机
    private final List<Bullet> bullets;                     // 所有子弹
    private final Deque<CollisionPairs> hit;                // 所有命中
    private final BulletThread bulletThread;                // 子弹管理线程
    private final ShipThread shipThread;                    // 敌方飞船管理线程
    private final HitThread hitThread;                      // 命中管理线程
    private final SprinkleThread sprinkleThread;            // 抛洒管理线程
    private final ExecutorService executor = Executors.newFixedThreadPool(3);  // 计算线程池
    private int process = 0;                                // 难度

    public GameJudgeTask(GameState gameState, Plane myPlane, List<Ship> ships, Deque<CollisionPairs> hit, List<Bullet> bullets) {
        this.gameState = gameState;
        this.myPlane = myPlane;
        this.ships = ships;
        this.hit = hit;
        this.bullets = bullets;
        this.gameState.put("destroy", 0);
        // 启动子弹管理线程
        bulletThread = new BulletThread(bullets);
        bulletThread.start();
        // 启动敌机管理线程
        shipThread = new ShipThread(ships);
        shipThread.start();
        // 启动命中管理线程
        hitThread = new HitThread(hit);
        hitThread.start();
        sprinkleThread = new SprinkleThread(ships, bullets);
        sprinkleThread.start();
    }

    @Override
    public void run() {
        // 检查碰撞
        Future<List<CollisionPairs>> touchCheck = executor.submit(() -> {
            // 检查玩家
            if (bullets.stream()
                    // 检查是否同阵营
                    .filter(bullet -> myPlane.getCamp() != bullet.getCamp())
                    .anyMatch(bullet -> {
                        if (bullet.isDestroy()) return false;
                        boolean b = Utils.isEdgeCollision(myPlane, bullet);
                        if (b) bullet.setDestroy(true);
                        return b;
                    })) {
                myPlane.injury();
            }
            // 检查玩家与敌方飞机
            if (ships.stream()
                    .anyMatch(ship -> {
                        if (ship.isDestroy()) return false;
                        boolean b = Utils.isEdgeCollision(myPlane, ship);
                        if (b) ship.setDestroy(true);
                        return b;
                    })) {
                myPlane.injury();
            }
            // 检查其他
            List<CollisionPairs> s = ships.stream()
                    .flatMap(ship -> bullets.stream()
                            // 检查是否同阵营
                            .filter(bullet -> ship.getCamp() != bullet.getCamp())
                            // 检查是否已摧毁
                            .filter(bullet -> !ship.isDestroy() && !bullet.isDestroy())
                            // 颜色是否相同
                            .filter(bullet -> bullet.getColor().equals(ship.getColor()))
                            // 检查是否碰撞
                            .filter(bullet -> Utils.isEdgeCollision(ship, bullet))
                            // 组合为碰撞对
                            .map(bullet -> {
                                ship.injury();
                                bullet.setDestroy(true);
                                return new CollisionPairs(ship, bullet);
                            }))
                    .collect(Collectors.toList());
            gameState.put("destroy", s.size());
            return s;
        });

        // 检查是否超过到终点
        Future<Integer> achieveCheck = executor.submit(() -> (int) ships.stream()
                .filter(ship -> ship.getY() > BATTLEFIELD_HEIGHT + ship.getHeight())
                .peek(ship -> ship.setDestroy(true))
                .count());

        // 检查射击情况
        Future<List<Ship>> attackCheck = executor.submit(() -> {
            List<Ship> s = ships.stream()
                    // 已摧毁无法发射
                    .filter(Predicate.not(Ship::isDestroy))
                    // 查看发射情况
                    .filter(Ship::isShooting).toList();
            if (myPlane.isShooting()) {
                s = new ArrayList<>(s);
                s.add(myPlane);
            }
            return s;
        });

        try {
            // 添加子弹
            attackCheck.get()
                    .forEach(ship -> {
                        Bullet bullet = new Bullet(ship.getCamp(), ship.getBulletSpeed());
                        bullet.setX(ship.getX() + (ship.getWidth() - bullet.getWidth()) / 2);
                        bullet.setY(ship.getY() + (ship.getHeight()) / 2);
                        bullet.setColor(ship.getColor());
                        if (ship.getCamp() == FRIENDLY_CAMP) {
                            bullet.setY(ship.getY() - (ship.getHeight()) / 2);
                        } else {
                            bullet.setY(ship.getY() + (ship.getHeight()) / 2);
                        }
                        bullets.add(bullet);
                    });
            // 添加命中
            hit.addAll(touchCheck.get());
            // 计算漏掉的飞机并扣除生命
            for (int i = 0; i < achieveCheck.get(); i++) {
                myPlane.injury();
            }
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
        if (myPlane.isChange()) {
            ColorE[] colorEs = gameState.get("blockEs");
            int i = (myPlane.getX() + myPlane.getWidth() / 2 + 10) / COLOR_BLOCK_WIDTH;
            myPlane.setColor(colorEs[i].toString());
            myPlane.change();
            myPlane.setChange(false);
        }

        // 删除已摧毁的飞行物并记录
        int shipsCount = (int) ships.stream().filter(FlyObject::isDestroy).count();
        ships.removeIf(FlyObject::isDestroy);
        sprinkleThread.setShipsAmount(sprinkleThread.getShipsAmount() - shipsCount);
        int bulletsCount = (int) bullets.stream()
                .filter(bullet -> bullet.getCamp() == ENEMY_CAMP)
                .filter(FlyObject::isDestroy).count();
        bullets.removeIf(FlyObject::isDestroy);
        sprinkleThread.setBulletsAmount(sprinkleThread.getBulletsAmount() - bulletsCount);

        // 难度增加
        if ((Integer) gameState.get("score") / 50 > process) {
            process++;
            gameState.put("process", process);
            sprinkleThread.setCheckInterval(sprinkleThread.getCheckInterval() - 50);
            sprinkleThread.setBulletProbability(sprinkleThread.getBulletProbability() - 1);
            sprinkleThread.setShipsProbability(sprinkleThread.getShipsProbability() - 1);
            if (process % 2 == 0) {
                sprinkleThread.setSizeCoeff(sprinkleThread.getSizeCoeff() + 0.1);
                sprinkleThread.setShipUpperLimit(sprinkleThread.getShipUpperLimit() + 5);
                sprinkleThread.setBulletUpperLimit(sprinkleThread.getBulletUpperLimit() + 3);
                sprinkleThread.setSpeedCoeffS(sprinkleThread.getSpeedCoeffS() + 0.3);
                sprinkleThread.setSpeedCoeffB(sprinkleThread.getSpeedCoeffB() + 0.3);
            }
        }
    }

    @Override
    public boolean cancel() {
        bulletThread.setFlag(false);
        shipThread.setFlag(false);
        hitThread.setFlag(false);
        sprinkleThread.setFlag(false);
        return super.cancel();
    }
}
